--
-- Author: shunguo.chen
-- Date: 2017-12-26 18:46:25
--
-- PvpModel

local PvpInfo = import(".PvpInfo")
local PvpRewardVo = import(".PvpRewardVo")
local PvpLoadingInfo = import(".PvpLoadingInfo")
local PvpChampionSeasonInfo = import(".PvpChampionSeasonInfo")
local PvpChampionThroneTeam = import(".PvpChampionThroneTeam")
local PvpChampionFinalTeamInfo = import(".PvpChampionFinalTeamInfo")
local PvpChampionThroneGame = import(".PvpChampionThroneGame")
local BoxItemVo = require("app.reward.models.BoxItemVo")
local PvpChallengeSeasonInfo = import(".PvpChallengeSeasonInfo")
local PvpChallengeRewardVo = import(".PvpChallengeRewardVo")
local PvpDuelMemberVo = import(".PvpDuelMemberVo")
local PvpDuelRecordVo = import(".PvpDuelRecordVo")
local table_insert = table.insert

local fileName = string.getModeName(...)
local ClassRef = class(fileName, app.mvc.ModelBase)

local MATCH_MAX_TIME = 60
-- 实际时间，超过会匹配机器人
local MATCH_REAL_TIME = 30

-- 是否用测试数据
local _TEST = false

function ClassRef:ctor(data)
	self.super.ctor(self, data)
end

function ClassRef:init()
	self._pvpInfo = nil
	self._pvpChampionInfo = nil

	self._matchId = nil

	-- self._championNoticeData = {
	-- 	register = true,
	-- 	status = Enums.ChampionStatus.BATTLE
	-- }
end

-- 获取是非实时的，在确认是实时的情况下return的才准确
function ClassRef:getPvpInfo()
	-- 隔天过期，修改数据
	if self._pvpInfo and self._pvpInfo:isExpired() then
		self._pvpInfo:dayChange()
	end
	return self._pvpInfo
end

-- 获取冠军赛数据
function ClassRef:getChampionInfo()
	return self._pvpChampionInfo
end

-- 获取冠军赛 报名数据
function ClassRef:getThroneGame()
	return self._pvpChampionInfo:getThroneGame()
end

-- 获取冠军赛 每天的数据
function ClassRef:getThroneInfo(day)
	if not day then
		day = app:getWeekDay()
	end
	return self._pvpChampionInfo:getThroneInfo(day)
end

-- 获取冠军赛 队伍数据
function ClassRef:getThroneTeam()
	return self._pvpChampionThroneTeam
end

-- 获取冠军赛 胜负及排名信息
function ClassRef:getThroneRankInfo()
	return self._pvpChampionRankInfo
end

-- 获取冠军赛 决赛队伍数据
function ClassRef:getFinalTeamInfo()
	return self._pvpChampionFinalTeamInfo
end

-- 获取冠军赛 决赛阶段我自己的队伍数据
function ClassRef:getMyFinalTeamInfo()
	if not self._pvpChampionThroneTeam or not self._pvpChampionFinalTeamInfo then return nil end
	return self._pvpChampionFinalTeamInfo:getTeamInfoById(self._pvpChampionThroneTeam.teamId)
end

-- 获取冠军赛 获取冠军队伍数据
function ClassRef:getChampionTeam()
	if not self._pvpChampionFinalTeamInfo then return nil end
	return self._pvpChampionFinalTeamInfo:getChampionTeam()
end

-- 获取冠军赛 我的队伍是否获得了冠军
function ClassRef:checkIsChampion()
	if not self._pvpChampionThroneTeam or not self._pvpChampionFinalTeamInfo then return false end
	local championTeam = self._pvpChampionFinalTeamInfo:getChampionTeam()
	if championTeam and championTeam.teamId == self._pvpChampionThroneTeam.teamId then 
		return true
	end
	return false
end

-- 获取冠军赛 我的队伍是否已经被淘汰了
function ClassRef:checkMyTeamIsKnockOut()
	if not self._pvpChampionThroneTeam then return true end -- 没有队伍，默认被淘汰
	if not self._pvpChampionFinalTeamInfo then return false end
	if not self._pvpChampionFinalTeamInfo.isKnockOut then return false end -- 淘汰赛未开始

	local teamId = self._pvpChampionThroneTeam.teamId
	return self._pvpChampionFinalTeamInfo:checkIsKnockOut(teamId)
end

-- pvp宝箱数量
function ClassRef:getPvpBoxNum()
	local pvpInfo = self:getPvpInfo()
	if not pvpInfo then
		return 0
	end
	return pvpInfo:getBoxNum()
end

-- 打开pvp宝箱之后
function ClassRef:onOpenPvpBox()
	self._pvpInfo:openBox()
	app:sendMsg("PvpController", "onOpenBox", self._pvpInfo)
	EM:notify("onPvpBoxNumMayChange")
end

function ClassRef:getChallengeInfo()
	return self._pvpChallengeInfo
end

function ClassRef:refreshPvpInfoStarCount()
	if self._pvpInfo then
		self._pvpInfo:refreshStarCount()
	end
end

------------------------ receive ------------------------

-- pvp 信息更新(除了pvp战斗会对其有改变，还有支线任务也能获得pvp星章)
function ClassRef:S2C_TournamentInfo(msg)
	-- dump(msg, "S2C_TournamentInfo", 10)
	if msg.OK then
		local boxNumChange = true
		local recvInfo = msg.tournamentInfo
		if self._pvpInfo then
			local info = self._pvpInfo
			
			if info.seasonInfo.id == recvInfo.seasonInfo.id and not info:hasChangeCache() then
				-- 如果同一赛季，有等级变化无变化缓存，标记用来显示等级变化
				local oldLev = info.seasonInfo.lv
				local oldScore = info.seasonInfo.score

				info:init(recvInfo)
				info:setChangeCache(oldLev, oldScore)
			else
				info:init(recvInfo)
			end
		else
			self._pvpInfo = PvpInfo.new()
			self._pvpInfo:init(recvInfo)
		end
		app:sendMsg("PvpController", "onPvpInfoUpdate", self._pvpInfo)

	end
end

-- pvp 结果
-- message S2C_TournamentMatchResult {
--    int32 type = 1;
--    bool hasWon = 2;
--    repeated TournamentReward rewardList = 3;
--    TournamentInfo tournamentInfo = 10; --战斗结束后新的pvpInfo
-- }
function ClassRef:S2C_TournamentMatchResult(msg)
	-- if true then
	-- 	local data = {type = 303, hasWon = true, grade = 3, score = 300}
	-- 	local rewardList = {}
	-- 	for i = 1, 2 do
	-- 		local value = {}
	-- 		local reward = {}
	-- 		reward.rewardType = "challengeScore"
	-- 		reward.itemCount = 10
	-- 		value.rewardItem = reward
	-- 		rewardList[i] = value
	-- 	end
	-- 	data.rewardList = rewardList

	-- 	self:onChallengeMatchResult(data)
	-- 	return
	-- end

	-- dump(msg, "S2C_TournamentMatchResult", 10)
	
	local failStrs
	local info = self._pvpInfo
	local recvInfo = msg.tournamentInfo
	failStrs = info:getFailStrs(msg.type)

	if info.seasonInfo.id == recvInfo.seasonInfo.id and not info:hasChangeCache() then
		-- 如果同一赛季，有等级变化且无变化缓存，标记用来显示等级变化
		local oldLev = info.seasonInfo.lv
		local oldScore = info.seasonInfo.score

		info:init(recvInfo)
		info:setChangeCache(oldLev, oldScore)
	else
		info:init(recvInfo)
	end
	self._pvpInfo = info

	if msg.hasWon then
		local rewards = {}
		for i,v in ipairs(msg.rewardList) do
			rewards[i] = PvpRewardVo.new(v)
		end
		app:sendMsg("PvpController", "openWinView", rewards)
	else
		app:sendMsg("PvpController", "openFailView", failStrs)
	end
end


function ClassRef:S2C_WorldGuildWarBattleEnd(msg)
	if msg.won then
		app:sendMsg("PvpController", "openWinView", nil)
	else
		app:sendMsg("PvpController", "openFailView", nil)
	end
end

-- 重连／登陆后匹配消息同步，在匹配中需要恢复匹配
function ClassRef:S2C_CrossBattleInfo(msg)
	self._battleMatchMsg = msg

	-- 重连 进入地图后收到消息直接试着打开匹配界面
	-- 登陆 要等公告界面关闭后再试着打开匹配界面
	if MapManager:isEnterGame() then
		self:checkBattleMatch()
	end
end

function ClassRef:checkBattleMatch()
	if not self._battleMatchMsg then return end
	local msg = self._battleMatchMsg
	self._battleMatchMsg = nil
	if msg.matchStartTime > 0 and msg.targetID > 0 and msg.targetID ~= Enums.TeamTarget.eliteMatchArena then
		local serverTime = app.session:getServerTime() or app:getTime()
		local curTime = math.ceil(serverTime - msg.matchStartTime)
		-- print("serverTime, curTime", serverTime, curTime)
		if curTime < MATCH_REAL_TIME then
			self._matchId = msg.targetID
			app:sendMsg("PvpController", "openMatchView", MATCH_MAX_TIME, curTime)
		end
	end
end

-- 匹配成功
function ClassRef:onPvpMatchStart(msg)
	-- dump(msg, "PvpModel.onPvpMatchStart")
	EM:notify("onDisplayIndicator", false)
	app:sendMsg("PvpController", "openMatchView", MATCH_MAX_TIME)
end

-- 匹配失败
function ClassRef:onPvpMatchFail(msg)
	-- dump(msg, "PvpModel.onPvpMatchFail")
	app:sendMsg("PvpController", "closeMatchView")
	-- 清空LoadingModel 玩法id
	app:sendMsg("LoadingModel", "setPlayId")
	self._matchId = nil
end

-- 清理匹配
function ClassRef:clearPvpMatch()
	-- print("clearPvpMatch")
	self._matchId = nil
end

function ClassRef:onMapChanged()
	if self._loadingTargetID then
		self:reqFinishLoading(self._loadingTargetID)
	end
end

-- 重登／重连的主动设置
function ClassRef:setLoadingTargetID(id)
	self._loadingTargetID = id
end

-- 是否在pvpLoading中
function ClassRef:isInPvpLoading()
	return self._loadingTargetID ~= nil
end

-- pvploading 开始
function ClassRef:S2C_PVPLoadingOpen(msg)
	-- dump(msg, "S2C_PVPLoadingOpen", 10)
	self._loadingTargetID = msg.targetID
	local info = PvpLoadingInfo.new(msg)
	app:sendMsg("PvpController", "openLoadingView", info)
end

-- pvploading 更新
function ClassRef:S2C_PVPLoadingUpdate(msg)
	-- dump(msg, "S2C_PVPLoadingUpdate")
	app:sendMsg("PvpController", "updateLoadingView", msg.progressInfos)
end

-- pvploading 结束
function ClassRef:S2C_PVPLoadingClose(msg)
	-- dump(msg, "S2C_PVPLoadingClose")
	self._loadingTargetID = nil
	app:sendMsg("PvpController", "closeLoadingView")
	app:sendMsg("TheatreController", "onPvpLoadingClose")
end


-- 冠军赛报名 返回
function ClassRef:onChampionRegister(msg)
	-- print("---------------------onChampionRegister:", msg.registered, msg.memberCount)

	if not self._pvpChampionInfo then return end
	self._pvpChampionInfo:setRegister(msg.registered)
	
	if not msg.registered then 
		-- 取消报名成功，清空组队信息
		self._pvpChampionThroneTeam = nil
		self._pvpChampionInfo:setMemCount(0)
	else
		-- 报名成功，移除右下角的报名提示
		local deskController = UIHandler:getDesktopController()
		if deskController then
			deskController:removeFourthTipsByType( Constant.FUNC_TYPE_CHAMPION )
		end
	end

	app:sendMsg("PvpChampionController", "onChangeRegisterStatus")
	app:sendMsg("PvpController", "onChampionInfoUpdate", self._pvpChampionInfo)
end

-- 冠军赛组队信息 返回
function ClassRef:onChampionTeamInfo(msg)
	-- dump(msg, "onChampionTeamInfo")

	-- 拉取的是其他队伍信息
	if not msg.IsMyTeam then
		local throneTeam = nil
		local cb = nil
		if msg.Info then
			throneTeam = PvpChampionThroneTeam.new(msg.Info)
		end
		if throneTeam then
			executeFunc(self._reqOtherThroneTeamCB[throneTeam.teamId], throneTeam)
			self._reqOtherThroneTeamCB[throneTeam.teamId] = nil
		end
		return
	end

	local teamCount = 0
	if msg.Info then
		self._pvpChampionThroneTeam = PvpChampionThroneTeam.new(msg.Info)
		teamCount = self._pvpChampionThroneTeam:getMemCount()
	else
		-- print("team = nil")
		self._pvpChampionThroneTeam = nil
	end

	-- 设置赛季信息里面的memCount
	if self._pvpChampionInfo then
		self._pvpChampionInfo:setMemCount(teamCount)

		-- 更新界面
		if self._reqThroneTeamCB then 
			executeFunc(self._reqThroneTeamCB)
			self._reqThroneTeamCB = nil
		else
			if self._pvpChampionInfo:getRegister() then
				app:sendMsg("PvpChampionController", "onUpdateThroneTeamInfo")
				app:sendMsg("PvpController", "onChampionInfoUpdate", self._pvpChampionInfo)
			end
		end

	end
	
end

-- 冠军赛 胜负及排名 返回
function ClassRef:onChampionRankInfo(msg)
	-- dump(msg, "onChampionRankInfo")
	local info = {}
	info.wonTimes = msg.WonTimes or 0 
	info.lostTimes = msg.LostTimes or 0
	info.rank = msg.Rank or 0
	info.currentRound = msg.CurrentRound or 0
	info.score = msg.Score or 0 
	self._pvpChampionRankInfo = info

	app:sendMsg("PvpChampionController", "updateChampionRank", self._pvpChampionRankInfo)
	app:sendMsg("ChampionCopyController", "updateRoundCountDown")
	if self._reqThroneRankInfoCB then
		executeFunc(self._reqThroneRankInfoCB, self._pvpChampionRankInfo)
		self._reqThroneRankInfoCB = nil
	end
end

-- 冠军赛 决赛对战表
function ClassRef:onChampionFinalTeamInfo(msg)
	if not _TEST then
		self._pvpChampionFinalTeamInfo = PvpChampionFinalTeamInfo.new(msg)
	end

	if self._reqFinalTeamInfoCB then
		local myTeamId = 0
		if self._pvpChampionThroneTeam then myTeamId = self._pvpChampionThroneTeam.teamId end
		executeFunc(self._reqFinalTeamInfoCB, self._pvpChampionRankInfo, self._pvpChampionFinalTeamInfo, self:checkMyTeamIsKnockOut(), myTeamId)
		self._reqFinalTeamInfoCB = nil
	end

	-- 如果是淘汰赛阶段，需要去更新判断是否还有下一轮比赛
	if self._pvpChampionFinalTeamInfo.isKnockOut then
		app:sendMsg("ChampionCopyController", "updateRoundCountDown")
	end

	-- 如果已经决出冠军，就去拉取一次冠军赛季信息
	local championTeam = self:getChampionTeam()
	if championTeam and not self._hasPullChampionSeason then
		self._hasPullChampionSeason = true
		self:reqChampionSeasonInfo()
	end
end

-- 冠军赛 比赛结果
function ClassRef:onChampionBatttleResult(msg)
	-- print("IsWon:", msg.IsWon)

	local isWon = msg.IsWon
	local data = {}

	local function openResultView()
		-- dump(data, "onChampionBatttleResult.openResultView")
		if isWon then
			app:sendMsg("PvpController", "openChampionWinView", data)
		else
			app:sendMsg("PvpController", "openChampionFailView", data)
		end
	end

	local function analyStr(round)
		local str = ""
		if round == 0 then
			if isWon then
				str = L("Winthe64Round") -- L("赢得64强赛")
			else
				str = L("Losethe64Round") -- L("输掉64强赛")
			end
		elseif round == 1 then
			if isWon then
				str = L("Winthe32Round") -- L("赢得32强赛")
			else
				str = L("Losethe32Round") -- L("输掉32强赛")
			end
		elseif round == 2 then
			if isWon then
				str = L("WintheFristRound") -- L("你已进入八强")
			else
				str = L("LosetheFristRound") -- L("很遗憾，你止步于十六强")
			end
		elseif round == 3 then
			if isWon then
				str = L("WintheQuarterFinal") -- L("你已进入四强")
			else
				str = L("LosetheQuarterFinal") -- L("很遗憾，你止步于八强")
			end
		elseif round == 4 then
			if isWon then
				str = L("WintheSemiFinal") -- L("你已进入决赛")
			else
				str = L("LosetheSemiFinal") -- L("很遗憾，你止步于四强")
			end
		elseif round == 5 then
			if isWon then
				str = L("WintheFinal") -- L("你赢得了冠军！")
			else
				str = L("LosetheFinal") -- L("很遗憾，你输掉了决赛")
			end
		end

		data.szDesc = str
	end

	if self._pvpChampionInfo and self._pvpChampionRankInfo and self._pvpChampionFinalTeamInfo then -- 旧数据
		data.wonTimes = self._pvpChampionRankInfo.wonTimes + (isWon and 1 or 0)
		data.lostTimes = self._pvpChampionRankInfo.lostTimes + (isWon and 0 or 1)
		data.isKnockOut = self._pvpChampionFinalTeamInfo.isKnockOut
		if data.isKnockOut then
			local round = 0
			local teamInfo = self:getMyFinalTeamInfo()
			if teamInfo then round = teamInfo.round end
			analyStr(round)
		end

		openResultView()
	else

		-- 断线之后重现进入的，需要拉取冠军赛相关的几条协议, 同 NewActivityDungeonsModel -- 新数据
		-- self:reqChampionSeasonInfo()
		-- self:reqThroneTeamInfo()
		-- self:reqThroneRankInfo()
		-- self:reqThroneFinalTeamInfo(function()
		-- 	data.wonTimes = self._pvpChampionRankInfo.wonTimes
		-- 	data.lostTimes = self._pvpChampionRankInfo.lostTimes
		-- 	data.isKnockOut = false
		-- 	-- 是否在淘汰赛阶段 (如果刚好是预选赛的最后一场，有可能拉取回来的isKnockOut为true)
  --           local throneConfig = GD:queryThroneByDay(app:getWeekDay())
  --           if self._pvpChampionRankInfo.currentRound > tonumber(throneConfig.normalGameNum) then
  --               data.isKnockOut = true
  --           end

		-- 	if data.isKnockOut then
		-- 		local round = 0
		-- 		local teamInfo = self:getMyFinalTeamInfo()
		-- 		if teamInfo then round = teamInfo.round end
		-- 		if isWon then round = round - 1 end
		-- 		analyStr(round)
		-- 	end

		-- 	openResultView()
		-- end)

		data.isKnockOut = true
		data.szDesc = isWon and L("lua_code_text_387") or L("lua_code_text_200")
		openResultView()
	end
end

-- 冠军赛 下发某天16强队伍信息
function ClassRef:onThroneKnockOutTeams(msg)
	-- dump(msg, "onThroneKnockOutTeams")
	if not msg or not msg.teams then return end
	local teams = {}
	for _, data in ipairs(msg.teams) do
		local value = {}
		value.part = data.Part
		value.idx = data.Idx
		value.teamName = string.format(L("throneTeamName"), data.TeamName)
		value.round = data.Round
		value.teamId = data.TeamID
		value.throneTeam = PvpChampionThroneTeam.new()
		value.throneTeam:read(data, true)

		table.insert(teams, value)
	end

	local function sortTeams(a, b)
		if a.part == b.part then
			return a.idx < b.idx
		else
			return a.part < b.part
		end
	end

	table.sort(teams, sortTeams)
	for i, data in ipairs(teams) do
		data.index = i -- 1-16
	end

	executeFunc(self._reqThroneKnockOutTeamCB, teams, msg.results)
	self._reqThroneKnockOutTeamCB = nil
end

-- 冠军赛，服务器下发当前阶段信息
-- 登录，报名截止，准备阶段，结束
function ClassRef:onNotifyChampionStatus(msg)
	local day = app:getWeekDay()
	local throneConfig = GD:queryThroneByDay(day)
	if not throneConfig then return end
	-- print(msg.registered)

	-- 获取服务器时间结构
	local timeDate = app.session:getServerDate()

	local function getTranslateTime(stringValue)
		local values = string.split(stringValue, "|")
		local intervalTime = tonumber(values[1]) * 3600 + tonumber(values[2]) * 60 - timeDate.hour * 3600 - timeDate.min * 60 - timeDate.sec
		return app.session:getServerTime() + intervalTime
	end

	local data = {}
	data.RegOpenTime = getTranslateTime(throneConfig.enterStartTime)
	data.RegCloseTime = getTranslateTime(throneConfig.enterEndTime)
	data.PrepareTime = getTranslateTime(throneConfig.enterBattlefieldTime)
	data.BattleStartTime = getTranslateTime(throneConfig.battleTime1)
	data.CloseTime = getTranslateTime(throneConfig.closeTime)
	data.register = msg.registered
	data.teamMemCount = 0

	self._championNoticeData = PvpChampionThroneGame.new()
	self._championNoticeData:read(data)
	self._championNoticeData.status = self._championNoticeData:checkChampionStatus()

	-- 通知到 tasktrackview 里，是否显示冠军赛对应的item
	EM:notify("onTaskTrackChange")
	self:setChampionNotice()

	-- local value = {}
	-- value.isOpen = true
	-- value.playId = 901
	-- value.startTime = 1547107200
	-- value.endTime = 1547110800
	-- value.state = "idle"
	-- self:onChallengeOpenInfo(value)
end

function ClassRef:getChampionStatusData()
	return self._championNoticeData	
end

function ClassRef:setChampionNotice()
	-- 第一次登陆进游戏，如果未报名，显示 右下角报名通知
	if not self._championNoticeData or self._notifyChampionStatus then return end
	
	if not self._championNoticeData.register and self._championNoticeData.status == Enums.ChampionStatus.REGISTER then
		-- 右下角的通知
		local params = {
			remindId = Constant.FUNC_TYPE_CHAMPION,
			dataTemp = 1
		}
		local desktopController = UIHandler:getDesktopController()
		if desktopController then
			self._notifyChampionStatus = true
			desktopController:insertFourthTips(params)
		end
	end
end

-- 匹配成功时，服务器下发通知
function ClassRef:onNotifyChampionTeamMactchSuccess(msg)
	self._championMatchSuccess = true
	self._notifyChampionMatchSuccess = false
	self:setChampionMatchSuccessNotice()
end

function ClassRef:setChampionMatchSuccessNotice()
	if not self._championMatchSuccess or self._notifyChampionMatchSuccess then return end
	
	-- 右下角的通知
	local params = {
		remindId = Constant.FUNC_TYPE_CHAMPION,
		dataTemp = 2
	}
	local desktopController = UIHandler:getDesktopController()
	if desktopController then
		self._notifyChampionMatchSuccess = true
		desktopController:insertFourthTips(params)
	end
end


-------------------------- 挑战赛相关 ---------------------------
-- 挑战赛 拉取挑战赛信息
function ClassRef:onGetChallengeInfo(msg)
	-- dump(msg, "onGetChallengeInfo")
	self._pvpChallengeInfo = PvpChallengeSeasonInfo.new(msg.seasonInfo)
	-- print("onGetChallengeInfo state:", self._pvpChallengeInfo:getState())
	app:sendMsg("PvpChallengeController", "onChallengeInfoUpdate", self._pvpChallengeInfo)
	app:sendMsg("PvpChallengeController", "refreshTeam")
	-- 同步更新state
	self:updateChallengeState(self._pvpChallengeInfo:getState(), self._pvpChallengeInfo:getStartStamp())
end

-- 挑战赛 匹配返回
function ClassRef:onChallengeMatch(msg)
	-- dump(msg, "onChallengeMatch", 10)

	-- 关闭组队投票界面
	app:sendMsg("NewTeamReadyAndSettingController", "closeView")

	-- 消息提示
	local reason = rawget(msg, "reason")
	local tipStr
	if reason == "LeaderCancel" then
	    tipStr = string.format(L("CrossServerTips10"), L("CrossServerTips8"))
	elseif reason == "MemberQuit" then
	    tipStr = L("CrossServerTips11")
	elseif reason == "EnterTeam" then
	    tipStr = L("CrossServerTips12")
	elseif reason == "MemberAdd" then
	    tipStr = L("CrossServerTips13")
	elseif reason == "LeaveTeam" then
	    tipStr = L("CrossServerTips20")
	end
	if tipStr then
	    local tipParams = {remindId=Constant.FUNC_TYPE_CROSS_MATCH, params=tipStr}
	    UIHandler:showThirdLevelTips(tipParams)
	end

	if not msg or not msg.ok then return end

	local isUpdate = false
	if self._pvpChallengeInfo then
		self._pvpChallengeInfo:readMatchInfo(msg.matchInfo)

		-- if not app:sendMsg("PvpChallengeController", "isChallengeShow") then
		-- 	app:sendMsg("PvpChallengeController", "openView")
		-- end
		app:sendMsg("PvpChallengeController", "onChallengeInfoUpdate", self._pvpChallengeInfo)
	end
	
	-- 同步更新state
	self:updateChallengeState(msg.matchInfo.state, msg.matchInfo.startStamp)
end

-- 挑战赛 取消匹配返回
function ClassRef:onChallengeCancelMatch(msg)
	if not msg or not msg.ok then return end

	if self._pvpChallengeInfo then
		self._pvpChallengeInfo:readMatchInfo(msg.matchInfo)
		app:sendMsg("PvpChallengeController", "onChallengeInfoUpdate", self._pvpChallengeInfo)
	end
	
	-- 同步更新state
	self:updateChallengeState(msg.matchInfo.state, msg.matchInfo.startStamp)
end

-- 挑战赛 通知客户端准备
function ClassRef:onChallengePrepareNotify(msg)
	self._challengPrepareNotify = msg
	if self._pvpChallengeInfo then
		self._pvpChallengeInfo:setState("prepare")
		app:sendMsg("PvpChallengeController", "onChallengeInfoUpdate", self._pvpChallengeInfo)
	end
	-- 设置结束时间
	if msg.readyNum == 0 then
		self._challengePrepareEndTime = app.session:getServerTime() + 30 -- 倒计时30s
	end
	-- 同步更新state
	self:updateChallengeState("prepare")

	-- 边界条件判断
	if BattleManager:isInBattle() or BattleManager:isWaitBattle() then -- 如果在战斗中，退出战斗
		-- BattleManager:goOutBattle()
		BattleUIEvent:dispatchEvent(BattleUIEvent.TYPE.BATTLE_ESCAPE)
	elseif StoryManager:isEnterStoryMode() then -- 在剧情中,强制结束当前剧情
		-- display.pushToast(L("挑战赛匹配成功，请打开准备界面"))
		StoryManager:forceExitCurStory()
	else 
		-- 如果正在进行一些操作，就stop，停止追踪
		app:getLaunchCtl():endCharacterMove()
		-- 关闭宝箱界面
		app:sendMsg("BoxController", "closeView")
	end

	app:sendMsg("PvpChallengeController", "updateChallengePrepare", msg)
end

-- 挑战赛 获取prepareNotify
function ClassRef:getChallengePrepareNotify()
	return self._challengPrepareNotify
end

-- 挑战赛 获取准备结束时间
function ClassRef:getChallengePrepareEndTime()
	if not self._challengePrepareEndTime then
		self._challengePrepareEndTime = app.session:getServerTime() + 30
	end
	return self._challengePrepareEndTime
end

-- 挑战赛 客户端请求准备 或 取消准备
function ClassRef:onChallengeClientPrepare(msg)
end

-- 挑战赛 服务器通知惩罚信息
function ClassRef:onChallengePunishNotify(msg)
	if not msg.mySelf then
		local tipParams = {remindId=Constant.FUNC_TYPE_CROSS_MATCH, params=L("CrossServerTips14")}
		UIHandler:showThirdLevelTips(tipParams)
	end
	if self._pvpChallengeInfo then
		self._pvpChallengeInfo:readMatchInfo(msg.matchInfo)
		app:sendMsg("PvpChallengeController", "onChallengeInfoUpdate", self._pvpChallengeInfo)
	end
	-- 同步更新state
	-- print("punishNotify:", msg.matchInfo.state, msg.matchInfo.startStamp)
	self:updateChallengeState(msg.matchInfo.state, msg.matchInfo.startStamp)
end

-- 挑战赛 服务器通知当前开启状态（登录游戏，开始挑战赛，结束挑战赛）,另外当state有改变时也会通知（除了客户端主动请求的）
function ClassRef:onChallengeOpenInfo(msg)
	-- 通知挑战赛结束，正在匹配中的话弹出提示
	if not msg.isOpen then
		if self._challengeStatus and self._challengeStatus.isOpen and self._challengeStatus.state == "matching" then
			display.pushToast(L("challengeTips12"))
		end
	end

	local data = {}
	data.isOpen = msg.isOpen
	data.playId = msg.playId
	data.startTime = msg.startTime
	data.endTime = msg.endTime
	data.state = msg.state
	data.startMatchStamp = msg.startMatchStamp
	if not data.isOpen then
		data.state = "idle"
	end
	-- dump(data, "PvpModel._challengeStatus")
	self._challengeStatus = data
	if self._pvpChallengeInfo then
		self._pvpChallengeInfo:setState(msg.state)
		app:sendMsg("PvpChallengeController", "onChallengeInfoUpdate", self._pvpChallengeInfo)
	end

	-- 同步更新state
	self:updateChallengeState(msg.state, msg.startMatchStamp)
end

-- 挑战赛开启中
function ClassRef:isChallengeOpen()
	if self._challengeStatus then
		return self._challengeStatus.isOpen
	end
	return false
end

-- 精英赛匹配过程中
function ClassRef:isInChallengeMatch()
    if self._challengeStatus then
        return self._challengeStatus.state == "matching"
    end
    return false
end

function ClassRef:getChallengeStatusData()
	return self._challengeStatus
end

function ClassRef:getChallengePlayId()
	if self._challengeStatus then
		return self._challengeStatus.playId
	end
	return 0
end

function ClassRef:getOpenChallengeRankId()
	if not self._challengeStatus then return 0 end

	local playId = self._challengeStatus.playId
	local challengeInfo = GD:getChallengeInfo(playId)
	return tonumber(challengeInfo.rankId)
end

-- 挑战赛 更新state, startMatchStamp只在state == "matching" 才有效
function ClassRef:updateChallengeState(state, startMatchStamp)
	if not startMatchStamp then startMatchStamp = 0 end

	if self._challengeStatus then
		local preIsInMatch = self:isInChallengeMatch()
		self._challengeStatus.state = state
		self._challengeStatus.startMatchStamp = startMatchStamp

		-- 通知到 tasktrackview 里，是否显示挑战赛对应的item
		EM:notify("onTaskTrackChange")

		app:sendMsg("NewActivityDungeonsController", "updateChallengeStatus",
			self._challengeStatus)

		local curIsInMatch = self:isInChallengeMatch()
		app:sendMsg("TeamModel", "updateTeamCrossMatch", Enums.TeamTarget.challenge, curIsInMatch)
		app:sendMsg("TeamModel", "updateTeamCrossMatch", self._challengeStatus.playId, curIsInMatch)

		if curIsInMatch ~= preIsInMatch then
			EM:notify("onChallengeMatchChange", curIsInMatch)
		end
	end

	-- 关闭准备界面
	if state ~= "prepare" then
		self._challengPrepareNotify = nil
		app:sendMsg("PvpChallengeController", "closeChallengePrepare")
	end

	if self._pvpChallengeInfo then
		app:sendMsg("NewActivityDungeonsController", "updateChallengeInfo",
			self._pvpChallengeInfo)
	end
end

-- 挑战赛 服务器通知结算
function ClassRef:onChallengeMatchResult(msg)
	-- dump(msg, "onChallengeMatchResult")

	self._pvpChallengeInfo = PvpChallengeSeasonInfo.new(msg.seasonInfo)

	local rewards = {}
	for i, data in ipairs(msg.rewardList) do
		local reward = PvpChallengeRewardVo.new(data)
		if reward.itemData then
			table.insert(rewards, reward)
		end
	end

	local winTimes = self._pvpChallengeInfo:getWinTimes() or 0
	local dailyScore = self._pvpChallengeInfo:getDailyScore() or 0
	-- 胜利的时候加上胜场奖励(#rewards为0表示已经达到奖励上限，不显示胜场奖励，显示tips)--#rewards > 0
	if msg.hasWon and #rewards > 0 then
		local data = UD:parseRewardToBagItem("4001|0|1")
		table.insert(rewards, {itemData = data})
	end
	app:sendMsg("PvpController", "openChallengeResultView", msg.type, msg.hasWon, rewards, msg.grade, msg.score, dailyScore, winTimes)
end

-- 挑战赛 服务器返回检查匹配条件
function ClassRef:onChallengeCheckMatchCondition(msg)
	-- dump(msg, "onChallengeCheckMatchCondition")
	if msg and msg.ok then
		executeFunc(self._checkChallengeMatchCB)
	end
	self._checkChallengeMatchCB = nil
end

-- 挑战赛 服务器返回再来一局
function ClassRef:onChallengeOneMoreGame(msg)
end

----------------------------------------- request ------------------------------------
-- 地图loading结束之后，请求pvpLoading结束
function ClassRef:reqFinishLoading(targetID)
	-- print("C2S_PVPLoadingFinish", targetID)
	app.session:request("pb_pvploading.C2S_PVPLoadingFinish",{targetID=targetID})

	if Enums.TeamTarget.duel == targetID then
        app:sendMsg("PvpModel", "S2C_PVPLoadingClose")
    end
end

-- 获取pvpInfo ()
function ClassRef:reqPvpInfo()
	-- print("PvpModel:reqPvpInfo")
    -- app.session:request("tournament.C2S_GetTournamentInfo",{})
end

-- 获取赛季奖励
function ClassRef:reqSessionReward()
    app.session:request("tournament.C2S_GetTournamentSeasonReward",{},function(msg)
    	-- dump(msg, "C2S_GetTournamentSeasonReward", 10)
    	if msg.OK then
			self._pvpInfo:clearLastSeasonReward()
        end

        local items = {}
        local item
        for i,v in ipairs(msg.rewardList) do
            -- 凑出BoxView的数据
            items[i] = BoxItemVo.new({loot = v})
        end
        items = table.randomCnt(items)
        app:sendMsg("BoxController", "onOpenBox", items)
    end, nil, function(errMsg)
	    app:sendMsg("BoxController", "closeView")
    end)
end

-- 开始pvp匹配
function ClassRef:reqPvpMatch(id)
	if self._matchId then
		release_print("PvpModel.reqPvpMatch", self._matchId, id)
		display.pushToast(L("ErrOperationTooFrequent"))
		return
	end
	
	self._matchId = id
	EM:notify("onDisplayIndicator", true)

	local errorCB = function()
		EM:notify("onDisplayIndicator", false)
		self:onPvpMatchFail()
	end
	if id == Enums.TeamTarget.arena then
		app.session:request("pb_arena.C2S_ArenaMatch",{}, nil, nil, errorCB)
	elseif id == Enums.TeamTarget.chess then
		app.session:request("pb_starchess.C2S_StarChessMatch", {}, nil, nil, errorCB)
	elseif id == Enums.TeamTarget.melee then
		app.session:request("pb_melee.C2S_MeleeMatch", {}, nil, nil, errorCB)
	elseif id == Enums.TeamTarget.theatre then
		app.session:request("pb_theatre.C2S_TheatreMatch", {}, nil, nil, errorCB)
	elseif id == Enums.TeamTarget.kof then
		app.session:request("pb_kingofduel.C2S_KingOfDuelMatch", {}, nil, nil, errorCB)
	elseif id == Enums.TeamTarget.eliteMatchArena then
		-- 是湿等，直接清理掉为干等相关的数据
		errorCB()
		UD.csEliteMatch:C2S_CombatCrossMatch(id)
	elseif id == Enums.TeamTarget.challenge then
		-- 是湿等，直接清理掉为干等相关的数据
		errorCB()
		self:reqChallengeMatch()
	end
end

-- 取消pvp匹配
function ClassRef:reqPvpCancel()
	local errorCB = function()
		self:onPvpMatchFail()
	end
	if self._matchId == Enums.TeamTarget.arena then
		app.session:request("pb_arena.C2S_ArenaCancel",{}, nil, nil, errorCB)
	elseif self._matchId == Enums.TeamTarget.chess then
		app.session:request("pb_starchess.C2S_StarChessCancel",{}, nil, nil, errorCB)
	elseif self._matchId == Enums.TeamTarget.melee then
		app.session:request("pb_melee.C2S_MeleeCancel",{}, nil, nil, errorCB)
	elseif self._matchId == Enums.TeamTarget.theatre then
		app.session:request("pb_theatre.C2S_TheatreCancel",{}, nil, nil, errorCB)
	elseif self._matchId == Enums.TeamTarget.kof then
		app.session:request("pb_kingofduel.C2S_KingOfDuelCancel",{}, nil, nil, errorCB)
	else

	end
	self._matchId = nil
end

-- 获取冠军赛季信息
function ClassRef:reqChampionSeasonInfo(cb)
	-- print("--------->    reqChampionSeasonInfo")

	if _TEST then
		self._pvpChampionInfo = PvpChampionSeasonInfo.new()
		self._pvpChampionInfo:test()
		app:sendMsg("PvpController", "onChampionInfoUpdate", self._pvpChampionInfo)
		return
	end

	app.session:request("pb_throne.C2S_ThroneSeasonInfo", {}, function(msg)
		self._pvpChampionInfo = PvpChampionSeasonInfo.new(msg)
		-- dump(self._pvpChampionInfo)
		app:sendMsg("PvpController", "onChampionInfoUpdate", self._pvpChampionInfo)
		app:sendMsg("PvpChampionController", "updateChampionCharacter", self._pvpChampionInfo)

		-- 更新冠军赛红点
		app:sendMsg("PvpController", "updateChampionRedPoint")
		executeFunc(cb)
	end, {block=true})
end

-- 冠军赛报名或取消报名
function ClassRef:reqRegister(bRegister)
	if self._pvpChampionInfo:getRegister() == bRegister then return end
	-- print("--------->    reqRegister:", bRegister)
	app.session:request("pb_throne.C2S_RegisterThrone", {register = bRegister, teamName = "", icon = 5})
end


-- 冠军赛 拉取报名的队伍信息
function ClassRef:reqThroneTeamInfo(cb)
	-- print("--------->    reqThroneTeamInfo")
	
	if _TEST then
		self._pvpChampionThroneTeam = PvpChampionThroneTeam.new()
		self._pvpChampionThroneTeam:test()
		executeFunc(cb)
		return
	end

	if self._pvpChampionInfo and not self._pvpChampionInfo:getRegister() then
		self._pvpChampionThroneTeam = nil
		executeFunc(cb)
	else
		self._reqThroneTeamCB = cb
		app.session:request("pb_throne.C2S_ThroneTeamInfo", {})
	end
	
end

-- 冠军赛 进入准备场
function ClassRef:reqEnterThroneMap()
	-- 跨服匹配中，不能进入冠军赛
	if app:sendMsg("TeamModel", "isInCrossMatch") then
        display.pushToast(L("CrossServerTips5"))
        return
    end

    -- 跨服副本中，不能进入跨服公会战
    if DungeonManager:isCrossDungeon() then
        display.pushToast(L("CrossServerTips26"))
        return
    end

	-- print("--------->     reqEnterThroneMap")
	app.session:request("pb_throne.C2S_EnterThroneMap", {})
end

-- 冠军赛 请求胜负及排名
function ClassRef:reqThroneRankInfo(cb)
	-- print("--------->     reqThroneRankInfo")
	self._reqThroneRankInfoCB = cb
	
	if _TEST then
		self:onChampionRankInfo({WonTimes = 0, LostTimes = 0, Rank = 100, CurrentRound = 0, Score = 0})
		return
	end
	app.session:request("pb_throne.C2S_ThroneRankInfo", {})

end

-- 冠军赛 请求拉取决赛信息
function ClassRef:reqThroneFinalTeamInfo(cb)
	-- print("--------->     reqThroneFinalTeamInfo")

	self._reqFinalTeamInfoCB = cb

	if _TEST then
		self._pvpChampionFinalTeamInfo = PvpChampionFinalTeamInfo.new()
		self._pvpChampionFinalTeamInfo:test()
		self:onChampionFinalTeamInfo()
		return
	end

	app.session:request("pb_throne.C2S_ThroneKnockOutInfo", {})
end

-- 冠军赛 根据队伍ID拉去队伍信息
function ClassRef:reqThroneTeamById(teamId, cb)
	if not teamId then
		executeFunc(cb, nil)
		return
	end

	-- print("reqThroneTeamById ->", teamId)

	if _TEST then
		executeFunc(cb, self._pvpChampionThroneTeam)
		return
	end

	if self._reqOtherThroneTeamCB == nil then
		self._reqOtherThroneTeamCB = {}
	end
	self._reqOtherThroneTeamCB[teamId] = cb
	app.session:request("pb_throne.C2S_ThroneTeamInfo", {TeamID = teamId})
end

-- 冠军赛领取宝箱
function ClassRef:reqGetChampionReward(type)
	-- print("reqGetChampionReward --> ", type)

	app.session:request("pb_throne.C2S_ThroneGetReward", {type = type}, function(ret)
		if ret.ok then
			-- print("2222222222222")
			local items = {0,0,0,0,0}
			for i,v in ipairs(ret.luckItems) do
				items[i] = BoxItemVo.new(v)
			end
			items = table.randomCnt(items)
			app:sendMsg("BoxController", "onOpenBox", items)

			self:reqChampionSeasonInfo() -- 领取成功，重新拉取赛季信息
		end
	end)
end

-- 冠军赛查看 其他天的对战信息
function ClassRef:reqThroneKnockOutTeam(day, cb)
	-- print("reqThroneKnockOutTeam --> ", day)

	self._reqThroneKnockOutTeamCB = cb
	app.session:request("pb_throne.C2S_ThroneKnockOutTeams", {gameID = day})
end


-- 拉取挑战赛信息
function ClassRef:reqChallengeInfo()
	-- print("reqChallengeInfo")

	if _TEST then
		local challengeInfo = PvpChallengeSeasonInfo.new()
		challengeInfo:test()
		self._pvpChallengeInfo = challengeInfo
		app:sendMsg("PvpChallengeController", "onChallengeInfoUpdate", challengeInfo)
		return
	end

	app.session:request("pb_challenge.C2S_GetChallengeInfo", {})
end

-- 检查队员是否满足挑战赛匹配条件
function ClassRef:reqCheckChallengeMatchCondition(cb)
	self._checkChallengeMatchCB = cb
	app.session:request("pb_challenge.C2S_ChallengeCheckMatchCondition", {})
end

-- 请求挑战赛匹配
function ClassRef:reqChallengeMatch()
	-- print("reqChallengeMatch")

	if _TEST then
		self._pvpChallengeInfo.matchInfo.state = "matching"
		self:onGetChallengeInfo({seasonInfo = self._pvpChallengeInfo})
		return
	end

	app.session:request("pb_challenge.C2S_ChallengeMatch", {})
end

-- 请求挑战赛取消匹配
function ClassRef:reqChallengeCancelMatch()
	-- print("reqChallengeCancelMatch")

	if _TEST then
		self._pvpChallengeInfo.matchInfo.state = "idle"
		self:onGetChallengeInfo({seasonInfo = self._pvpChallengeInfo})
		return
	end

	app.session:request("pb_challenge.C2S_ChallengeCancel", {})
end

function ClassRef:reqMatchingReady(bReady)
	-- print("reqMatchingReady", bReady)
	app.session:request("pb_challenge.C2S_ChallengePrepare", {prepare = bReady})
end

-- 请求挑战赛再来一局
function ClassRef:reqChallengeOneMoreGame(agree)
	-- print("reqChallengeOneMoreGame", agree)
	app.session:request("pb_challenge.C2S_ChallengeOneMoreGame", {restart = agree})
end

-- 获取挑战赛赛季奖励
function ClassRef:reqChallengeSeasonReward()
    app.session:request("pb_challenge.C2S_GetChallengeSeasonReward",{},function(msg)
    	-- dump(msg, "S2C_GetChallengeSeasonReward")
    	if msg.OK and self._pvpChallengeInfo then
    		self._pvpChallengeInfo:clearLastSeasonReward()
        end

        local items = {}
        local item
        for i,v in ipairs(msg.rewardList) do
            -- 凑出BoxView的数据
            items[i] = BoxItemVo.new({loot = v})
        end
        items = table.randomCnt(items)
        app:sendMsg("BoxController", "onOpenBox", items)
    end, nil, function(errMsg)
	    app:sendMsg("BoxController", "closeView")
    end)
end

-- 决斗赛
function ClassRef:reqDuelInfo()
	-- print("reqDuelInfo")
	app.session:request("pb_duel.C2S_GetDuelInfo", {}, function(msg)
		--init 那边直接监听了
	end,{block = true})
end


function ClassRef:onDuelInfo(msg)
	-- dump(msg, "onDuelInfo")
	local duelMyInfo = PvpDuelMemberVo.new(msg.myInfo)
	local opponentInfos = {}
	for k,v in ipairs(msg.enemyList) do
		table_insert(opponentInfos,PvpDuelMemberVo.new(v))
	end

	self._duelInfo = {myInfo = duelMyInfo, enemyList = opponentInfos}
	app:sendMsg( "PvpController", "refreshPvpDuelView",self._duelInfo)
end


function ClassRef:reqDuelOnBattlePartner(partnerId, isOnBattle)
	-- print("reqDuelOnBattlePartner", partnerId, isOnBattle)
	app.session:request("pb_duel.C2S_DuelOnBattlePartner", {id = partnerId, onBattle = isOnBattle}, function(msg)
		--init 那边直接监听了
		if msg.ok then
			--print("调整成功")
		end
	end,{block = true})
end

function ClassRef:getDuelInfo()
	return self._duelInfo
end


--购买挑战次数
function ClassRef:reqBuyDuelFightNum()
	--print("reqBuyDuelFightNum")
	app.session:request("pb_duel.C2S_DuelBuyChallengeTimes", {}, function(msg)
		--dump(msg, "C2S_DuelBuyChallengeTimes")
		if msg.ok then
			display.pushToast(L("tips_1080003"))
		end
	end,{block = true})
end

--查看决斗赛的对战记录
--[[
-- memberInfo enemy = 1; // 敌方信息
--	bool win = 2; // 是否胜利（非胜即负，没有平手）
--	int32 rankChange = 3; // 排名变动
--	string battleReportUrl = 4; // 战报播放地址（待开发）
--	int64 timestamp = 5; // 发生的时间戳
--]]
function ClassRef:reqDuelFightRecord()
	app.session:request("pb_duel.C2S_GetDuelBattleRecord", {}, function(msg)
		--dump(msg, "C2S_GetDuelBattleRecord")
		local records = msg.records
		if records then
			self._duelRecords = {}
			local num = #records
			if num > 0 then
				for i = num, 1, -1 do
					local recordVo = PvpDuelRecordVo.new(records[i])
					table_insert(self._duelRecords,recordVo)
				end
			end

			--通知去刷新战斗记录界面
			app:sendMsg( "PvpController", "openPvpDuelRecordView",self._duelRecords)
		end

	end,{block = true})
end

--单独刷新挑战角色
function ClassRef:reqDuelRefreshEnemy(pos)
	app.session:request("pb_duel.C2S_DuelRefreshEnemy", {pos = pos - 1}, function(msg)

	end,{block = true})
end


--开始duel挑战
function ClassRef:reqStartDuelFight(pos)
	-- print("reqStartDuelFight", pos)
	app.session:request("pb_duel.C2S_DuelStartChallenge", {pos = pos - 1}, function(msg)

	end,{block = true})
end


return ClassRef
